/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.src;
import java.io.*;
import java.util.*;
import java.text.MessageFormat;
import java.lang.reflect.Modifier;
import org.openide.TopManager;
import org.openide.cookies.SourceCookie;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.filesystems.Repository;
import org.openide.filesystems.FileObject;
/** Element that describes one class.
* Note that this is a member element--in fact, it may be either a
* top-level class (held in a source element), or a named inner class
* (held in another class element).
*
* @author Petr Hamernik, Jaroslav Tulach
*/
public final class ClassElement extends MemberElement {
/** Constant indicating that the class is a real class.
* @see #isClassOrInterface
*/
public static final boolean CLASS = true;
/** Constant indicating that the class is an interface.
* @see #isClassOrInterface
*/
public static final boolean INTERFACE = false;
/** Default class to extend.
* That is, <code>Object</code>.
*/
public static final Identifier ROOT_OBJECT = Identifier.create("java.lang.Object", "Object"); // NOI18N
/** Formats for the header - used in code generator */
private static final ElementFormat[] HEADER_FORMAT = {
new ElementFormat("{m,,\" \"}class {n}{s,\" extends \",}{i,\" implements \",}"), // NOI18N
new ElementFormat("{m,,\" \"}interface {n}{i,\" extends \",}") // NOI18N
};
/** source element we are attached to */
private SourceElement source;
//================ Constructors of ClassElement =================
static final long serialVersionUID =1692944638104452533L;
/** Create a new class element in memory.
*/
public ClassElement() {
this(new Memory (), null, null);
}
/** Factory constructor for defining embedded classes.
*
* @param impl implementation of functionality
* @param clazz the declaring class, or <code>null</code>
*/
public ClassElement(Impl impl, ClassElement clazz) {
this (impl, clazz, clazz.getSource ());
}
/** Factory constructor for defining top level classes.
* @param impl implementation of functionality
* @param source the source file this class is contained in, or <code>null</code>
*/
public ClassElement(Impl impl, SourceElement source) {
this (impl, null, source);
}
/**
* @param impl implementation of functionality
* @param clazz the declaring class
* @param source the source file to be presented in
*/
private ClassElement(Impl impl, ClassElement clazz, SourceElement source) {
super (impl, clazz);
this.source = source;
}
/** Clone this element.
* @return new element with the same values as the original,
* but represented in memory
*/
public Object clone () {
Memory mem = new Memory (this);
ClassElement el = new ClassElement (mem, null, null);
mem.copyFrom (this);
return el;
}
/** @return implemetation factory for this class
*/
final Impl getClassImpl () {
return (Impl)impl;
}
/** Implemented in ClassElement - update names of the constructors.
*/
void updateConstructorsNames(Identifier name) throws SourceException {
ConstructorElement[] c = getConstructors();
Identifier constrName = Identifier.create(name.getName());
for (int i = 0; i < c.length; i++)
c[i].setName(constrName);
}
//================ Main properties ==============================
/** Get the source element of this class.
* @return the source, or <code>null</code> if the class is not attached to any source
*/
public SourceElement getSource () {
return source;
}
/** Set whether this is really a class, or an interface.
* @param isClass one of {@link #CLASS} or {@link #INTERFACE}
* @throws SourceException if impossible
*/
public void setClassOrInterface(boolean isClass) throws SourceException {
getClassImpl ().setClassOrInterface (isClass);
}
/** Test whether this is really a class, or an interface.
* @return one of {@link #CLASS} or {@link #INTERFACE}
*/
public boolean isClassOrInterface() {
return getClassImpl ().isClassOrInterface ();
}
/** Test whether this is really a class.
* @return <code>true</code> if so
* @see #isClassOrInterface
*/
public boolean isClass() {
return getClassImpl ().isClassOrInterface ();
}
/** Test whether this is an interface.
* @return <code>true</code> if so
* @see #isClassOrInterface
*/
public boolean isInterface() {
return !getClassImpl ().isClassOrInterface ();
}
/** Test if this is an inner class.
* If so, it has a declaring class.
* @return <code>true</code> if so
* @see #ClassElement(ClassElement.Impl, ClassElement)
*/
public boolean isInner() {
return (getDeclaringClass() != null);
}
/* Get the modifiers of the class.
* @return the mask of possible modifiers for this element
* @see Modifier
*/
public int getModifiersMask() {
int ret = Modifier.PUBLIC | Modifier.ABSTRACT;
if (isClass()) {
ret |= Modifier.FINAL;
}
if (isInner()) {
ret |= Modifier.PROTECTED | Modifier.PRIVATE |
Modifier.STATIC | Modifier.FINAL;
}
return ret;
}
/** Set the name of this member.
* @param name the name
* @throws SourceException if impossible
*/
public final void setName(Identifier name) throws SourceException {
ClassElement c = getDeclaringClass();
String msg = null;
if (c != null) {
ClassElement c1 = c.getClass(name);
if ((c1 != null) && (c1 != this)) {
MessageFormat format = new MessageFormat(ElementFormat.bundle.getString("FMT_EXC_RenameClass"));
msg = format.format(new Object[] { c.getName().getName(), name });
}
}
else {
if (source != null) {
ClassElement c1 = source.getClass(name);
if ((c1 != null) && (c1 != this)) {
MessageFormat format = new MessageFormat(ElementFormat.bundle.getString("FMT_EXC_RenameClassInSource"));
msg = format.format(new Object[] { name });
}
}
}
if (msg != null) {
throw new SourceException(msg);
}
super.setName(name);
}
// ================= Super class =======================
/** Set the superclass of this class.
* @param superClass the superclass
* @throws SourceException if that is impossible
*/
public void setSuperclass(Identifier superClass) throws SourceException {
getClassImpl ().setSuperclass (superClass);
}
/** Get the superclass of this class.
* @return superclass identifier, or <code>null</code> (for interfaces, or possibly for classes with superclass <code>Object</code>)
*/
public Identifier getSuperclass() {
return getClassImpl ().getSuperclass ();
}
// ================= Initializers ========================
/** Add a new initializer block to this class.
* @param el the block to add
* @throws SourceException if impossible
*/
public void addInitializer (InitializerElement el) throws SourceException {
getClassImpl ().changeInitializers (
new InitializerElement[] { el }, Impl.ADD
);
}
/** Add some initializer blocks to this class.
* @param els the blocks to add
* @throws SourceException if impossible
*/
public void addInitializers (final InitializerElement[] els) throws SourceException {
getClassImpl ().changeInitializers (els, Impl.ADD);
}
/** Remove an initializer block from this class.
* @param el the block to remove
* @throws SourceException if impossible
*/
public void removeInitializer (InitializerElement el) throws SourceException {
getClassImpl ().changeInitializers (
new InitializerElement[] { el }, Impl.REMOVE
);
}
/** Remove some initializer blocks from this class.
* @param els the blocks to remove
* @throws SourceException if impossible
*/
public void removeInitializers (final InitializerElement[] els) throws SourceException {
getClassImpl ().changeInitializers (els, Impl.REMOVE);
}
/** Set the initializer blocks for this class.
* Any previous ones are just removed.
* @param els the new blocks
* @throws SourceException if impossible
*/
public void setInitializers (InitializerElement[] els) throws SourceException {
getClassImpl ().changeInitializers (els, Impl.SET);
}
/** Get all the initializer blocks for this class.
* @return all the blocks
*/
public InitializerElement[] getInitializers () {
return getClassImpl ().getInitializers ();
}
//================== Fields ===============================
/** Add a new field to the class.
* @param el the field to add
* @throws SourceException if impossible
*/
public void addField (FieldElement el) throws SourceException {
if (getField(el.getName()) != null)
throwAddException("FMT_EXC_AddField", el); // NOI18N
getClassImpl ().changeFields (new FieldElement[] { el }, Impl.ADD);
}
/** Add some new fields to the class.
* @param els the fields to add
* @throws SourceException if impossible
*/
public void addFields (final FieldElement[] els) throws SourceException {
for (int i = 0; i < els.length; i++)
if (getField(els[i].getName()) != null)
throwAddException("FMT_EXC_AddField", els[i]); // NOI18N
getClassImpl ().changeFields (els, Impl.ADD);
}
/** Remove a field from the class.
* @param el the field to remove
* @throws SourceException if impossible
*/
public void removeField (FieldElement el) throws SourceException {
getClassImpl ().changeFields (
new FieldElement[] { el }, Impl.REMOVE
);
}
/** Remove some fields from the class.
* @param els the fields to remove
* @throws SourceException if impossible
*/
public void removeFields (final FieldElement[] els) throws SourceException {
getClassImpl ().changeFields (els, Impl.REMOVE);
}
/** Set the fields for this class.
* Previous fields are removed.
* @param els the new fields
* @throws SourceException if impossible
*/
public void setFields (FieldElement[] els) throws SourceException {
getClassImpl ().changeFields (els, Impl.SET);
}
/** Get all fields in this class.
* @return the fields
*/
public FieldElement[] getFields () {
return getClassImpl ().getFields ();
}
/** Find a field by name.
* @param name the name of the field to look for
* @return the element or <code>null</code> if not found
*/
public FieldElement getField (Identifier name) {
return getClassImpl ().getField (name);
}
//================== Methods =================================
/** Add a method to this class.
* @param el the method to add
* @throws SourceException if impossible
*/
public void addMethod (MethodElement el) throws SourceException {
testMethod(el);
getClassImpl ().changeMethods (new MethodElement[] { el }, Impl.ADD);
}
/** Add some methods to this class.
* @param els the methods to add
* @throws SourceException if impossible
*/
public void addMethods (final MethodElement[] els) throws SourceException {
for (int i = 0; i < els.length; i++)
testMethod(els[i]);
getClassImpl ().changeMethods (els, Impl.ADD);
}
/** Test if the specified method already exists in the class.
* @param el The tested method
* @exception SourceException if method already exists in the class
*/
private void testMethod(MethodElement el) throws SourceException {
MethodParameter[] params = el.getParameters();
Type[] types = new Type[params.length];
for (int i = 0; i < types.length; i++)
types[i] = params[i].getType();
if (getMethod(el.getName(), types) != null)
throwAddException("FMT_EXC_AddMethod", el); // NOI18N
}
/** Remove a method from this class.
* @param el the method to remove
* @throws SourceException if impossible
*/
public void removeMethod (MethodElement el) throws SourceException {
getClassImpl ().changeMethods (
new MethodElement[] { el }, Impl.REMOVE
);
}
/** Remove some methods from this class.
* @param els the methods to remove
* @throws SourceException if impossible
*/
public void removeMethods (final MethodElement[] els) throws SourceException {
getClassImpl ().changeMethods (els, Impl.REMOVE);
}
/** Set the methods for this class.
* The old ones are removed.
* @param els the new methods
* @throws SourceException if impossible
*/
public void setMethods (MethodElement[] els) throws SourceException {
getClassImpl ().changeMethods (els, Impl.SET);
}
/** Get all methods in this class.
* @return the methods
*/
public MethodElement[] getMethods () {
return getClassImpl ().getMethods ();
}
/** Find a method by signature.
* @param name the method name to look for
* @param arguments the argument types to look for
* @return the method, or <code>null</code> if it was not found
*/
public MethodElement getMethod (Identifier name, Type[] arguments) {
return getClassImpl ().getMethod (name, arguments);
}
//================== Constructors ============================
/** Add a constructor to this class.
* @param el the constructor to add
* @throws SourceException if impossible
*/
public void addConstructor (ConstructorElement el) throws SourceException {
testConstructor(el);
getClassImpl ().changeConstructors (new ConstructorElement[] { el }, Impl.ADD);
}
/** Add some constructors to this class.
* @param els the constructors to add
* @throws SourceException if impossible
*/
public void addConstructors (final ConstructorElement[] els) throws SourceException {
for (int i = 0; i < els.length; i++)
testConstructor(els[i]);
getClassImpl ().changeConstructors (els, Impl.ADD);
}
/** Test if the specified constructor already exists in the class.
* @param el The tested constuctor
* @exception SourceException if constructor already exists in the class
*/
private void testConstructor(ConstructorElement el) throws SourceException {
MethodParameter[] params = el.getParameters();
Type[] types = new Type[params.length];
for (int i = 0; i < types.length; i++)
types[i] = params[i].getType();
if (getConstructor(types) != null)
throwAddException("FMT_EXC_AddConstructor", el); // NOI18N
}
/** Remove a constructor from this class.
* @param el the constructor to remove
* @throws SourceException if impossible
*/
public void removeConstructor (ConstructorElement el) throws SourceException {
getClassImpl ().changeConstructors (
new ConstructorElement[] { el }, Impl.REMOVE
);
}
/** Remove some constructors from this class.
* @param els the constructors to remove
* @throws SourceException if impossible
*/
public void removeConstructors (final ConstructorElement[] els) throws SourceException {
getClassImpl ().changeConstructors (els, Impl.REMOVE);
}
/** Set the constructors for this class.
* The old ones are replaced.
* @param els the new constructors
* @throws SourceException if impossible
*/
public void setConstructors (ConstructorElement[] els) throws SourceException {
getClassImpl ().changeConstructors (els, Impl.SET);
}
/** Get all constructors in this class.
* @return the constructors
*/
public ConstructorElement[] getConstructors () {
return getClassImpl ().getConstructors ();
}
/** Find a constructor by signature.
* @param arguments the argument types to look for
* @return the constructor, or <code>null</code> if it does not exist
*/
public ConstructorElement getConstructor (Type[] arguments) {
return getClassImpl ().getConstructor (arguments);
}
//================== Inner classes ==========================
/** Add a new inner class to this class.
* @param el the inner class to add
* @throws SourceException if impossible
*/
public void addClass (ClassElement el) throws SourceException {
if (getClass(el.getName()) != null)
throwAddException("FMT_EXC_AddClass", el); // NOI18N
getClassImpl().changeClasses(new ClassElement[] { el }, Impl.ADD);
}
/** Add some new inner classes to this class.
* @param el the inner classes to add
* @throws SourceException if impossible
*/
public void addClasses (final ClassElement[] els) throws SourceException {
for (int i = 0; i < els.length; i++) {
if (getClass(els[i].getName()) != null)
throwAddException("FMT_EXC_AddClass", els[i]); // NOI18N
}
getClassImpl ().changeClasses (els, Impl.ADD);
}
/** Remove an inner class from this class.
* @param el the inner class to remove
* @throws SourceException if impossible
*/
public void removeClass (ClassElement el) throws SourceException {
getClassImpl ().changeClasses (new ClassElement[] { el }, Impl.REMOVE);
}
/** Remove some inner classes from this class.
* @param els the inner classes to remove
* @throws SourceException if impossible
*/
public void removeClasses (final ClassElement[] els) throws SourceException {
getClassImpl ().changeClasses (els, Impl.REMOVE);
}
/** Set the inner classes for this class.
* The old ones are replaced.
* @param els the new inner classes
* @throws SourceException if impossible
*/
public void setClasses (ClassElement[] els) throws SourceException {
getClassImpl ().changeClasses (els, Impl.SET);
}
/** Get all inner classes for this class.
* @return the inner classes
*/
public ClassElement[] getClasses () {
return getClassImpl ().getClasses ();
}
/** Find an inner class by name.
* @param name the name to look for
* @return the inner class, or <code>null</code> if it does not exist
*/
public ClassElement getClass (Identifier name) {
return getClassImpl ().getClass (name);
}
//================== Implements =============================
/** Add an interface to this class.
* I.e., one which this class will implement.
* @param in the interface to add, by name
* @throws SourceException if impossible
*/
public void addInterface(Identifier in) throws SourceException {
getClassImpl ().changeInterfaces (new Identifier [] { in }, Impl.ADD);
}
/** Add some interfaces to this class.
* @param ins the interfaces to add, by name
* @throws SourceException if impossible
*/
public void addInterfaces(final Identifier[] ins) throws SourceException {
getClassImpl ().changeInterfaces (ins, Impl.ADD);
}
/** Remove an interface from this class.
* @param in the interface to remove. by name
* @throws SourceException if impossible
*/
public void removeInterfaces(Identifier in) throws SourceException {
getClassImpl ().changeInterfaces (new Identifier [] { in }, Impl.REMOVE);
}
/** Remove some interfaces from this class.
* @param ins the interfaces to remove, by name
* @throws SourceException if impossible
*/
public void removeInterface(final Identifier[] ins) throws SourceException {
getClassImpl ().changeInterfaces (ins, Impl.REMOVE);
}
/** Set the interfaces for this class.
* The old ones are replaced.
* @param ids the new interfaces, by name
* @throws SourceException if impossible
*/
public void setInterfaces(Identifier[] ids) throws SourceException {
getClassImpl ().changeInterfaces (ids, Impl.SET);
}
/** Get all interfaces for this class.
* I.e., all interfaces which this class implements (directly),
* or (if an interface) all interfaces which it extends (directly).
* @return the interfaces
*/
public Identifier[] getInterfaces () {
return getClassImpl ().getInterfaces ();
}
// ================ javadoc =========================================
/** Get the class documentation.
* @return the JavaDoc
*/
public JavaDoc.Class getJavaDoc() {
return getClassImpl ().getJavaDoc ();
}
// ================ printing =========================================
/* Print this element to an element printer.
* @param printer the printer to print to
* @exception ElementPrinterInterruptException if the printer cancels the printing
*/
public void print(ElementPrinter printer) throws ElementPrinterInterruptException {
printer.markClass(this, printer.ELEMENT_BEGIN);
JavaDoc doc = getJavaDoc();
if ((doc != null) && !doc.isEmpty()) {
printer.markClass(this, printer.JAVADOC_BEGIN); // JAVADOC begin
printJavaDoc(doc, printer);
printer.markClass(this, printer.JAVADOC_END); // JAVADOC end
printer.println(""); // NOI18N
}
printer.markClass(this, printer.HEADER_BEGIN); // HEADER begin
printer.print(isClass() ?
HEADER_FORMAT[0].format(this) :
HEADER_FORMAT[1].format(this)
);
printer.markClass(this, printer.HEADER_END); // HEADER end
printer.println(" {"); // NOI18N
printer.markClass(this, printer.BODY_BEGIN); // BODY begin
if (print(getInitializers(), printer)) {
printer.println(""); // NOI18N
printer.println(""); // NOI18N
}
if (print(getFields(), printer)) {
printer.println(""); // NOI18N
printer.println(""); // NOI18N
}
if (print(getConstructors(), printer)) {
printer.println(""); // NOI18N
printer.println(""); // NOI18N
}
if (print(getMethods(), printer)) {
printer.println(""); // NOI18N
printer.println(""); // NOI18N
}
print(getClasses(), printer);
printer.markClass(this, printer.BODY_END); // BODY end
printer.println(""); // NOI18N
printer.print("}"); // NOI18N
printer.markClass(this, printer.ELEMENT_END);
}
// ================ misc =========================================
/** This method just throws localized exception. It is used during
* adding some element, which already exists in class.
* @param formatKey The message format key to localized bundle.
* @param element The element which can't be added
* @exception SourceException is alway thrown from this method.
*/
private void throwAddException(String formatKey, MemberElement element) throws SourceException {
MessageFormat format = new MessageFormat(ElementFormat.bundle.getString(formatKey));
String msg = format.format(new Object[] { getName().getName(), element.getName().getName() });
throw new SourceException(msg);
}
/** Test whether this class has a declared main method
* and so may be executed directly.
* @return <CODE>true</CODE> if this class contains a
* <CODE>public static void main(String[])</CODE>
* method, otherwise <CODE>false</CODE>
*/
public boolean hasMainMethod() {
MethodElement[] methods = getMethods();
Identifier mainId = Identifier.create("main"); // NOI18N
for (int i = 0; i < methods.length; i++) {
MethodElement m = methods[i];
if (m.getName().equals(mainId)) {
if (m.getReturn() == Type.VOID) {
if ((m.getModifiers() & ~Modifier.FINAL) == Modifier.PUBLIC + Modifier.STATIC) {
MethodParameter[] params = m.getParameters();
if (params.length == 1) {
Type typ = params[0].getType();
if (typ.isArray()) {
typ = typ.getElementType();
if (typ.isClass()) {
if (typ.getClassName().getFullName().equals("java.lang.String")) { // NOI18N
return true;
}
}
}
}
}
}
}
}
return false;
}
// [PENDING] mustn't it also implement Serializable? --jglick
/** Test whether this class is a JavaBean.
* It must:
* <UL>
* <LI> be declared as public
* <LI> not be declared as abstract or an interface
* <LI> have a default public constructor
* </UL>
* Note that these are technical requirements: satisfying them
* does not imply that the class is really <em>intended</em>
* to be used as a JavaBean; this could have been accidental.
* @return <CODE>true</CODE> if this class could be a JavaBean,
* otherwise <CODE>false</CODE>
*/
public boolean isDeclaredAsJavaBean() {
if (Modifier.isPublic(getModifiers()) && !Modifier.isAbstract(getModifiers())) {
if (isClass()) {
ConstructorElement[] constructors = getConstructors();
for (int i = 0; i < constructors.length; i++) {
if (constructors[i].getParameters().length == 0)
if (Modifier.isPublic(constructors[i].getModifiers())) {
return true;
}
}
return (constructors.length == 0);
}
}
return false;
}
// [PENDING] concrete? public? what about extending [J]Applet indirectly? --jglick
/** Test whether this class is an applet.
* It must:
* <UL>
* <LI> be a class (not an interface)
* <LI> extend either {@link java.applet.Applet} or {@link javax.swing.JApplet}
* </UL>
* @return <CODE>true</CODE> if this class could be an applet,
* otherwise <CODE>false</CODE>.
*/
public boolean isDeclaredAsApplet() {
if (isClass()) {
Identifier superclass = getSuperclass();
if (superclass != null) {
String name = superclass.getFullName();
return name.equals("java.applet.Applet") || name.equals("javax.swing.JApplet"); // NOI18N
}
}
return false;
}
// ================ finders =======================================
/** List of finders
* @associates Finder*/
private static List finders = new LinkedList();
/** Register a new finder for locating class elements.
* @param f the finder to add
*/
public static void register (Finder f) {
synchronized (finders) {
finders.add (f);
}
}
/** Unregister a finder for locating class elements.
* @param f the finder to remove
*/
public static void unregister (Finder f) {
synchronized (finders) {
finders.remove (f);
}
}
/** Search for a class element throughout the system.
* First goes through repository and find the appropriate DataObject
* Tests if it has SourceCookie and if there exist the right one,
* it is returned. Otherwise tries to creates the Class.forName
* and asks all registered finders if they know where to find such a class.
*
* @param name class name separated by dots, e.g. <code>java.lang.String</code>.
* For inner classes is accepted delimiting by '$' or by '.'
* e.g. inner class A.B in package org.netbeans.test could
* be specified like: org.netbeans.A.B or org.netbeans.A$B
* Both possibilities are accepted.
* @return class element for that name, or <code>null</code> if none exists
* @see ClassElement.Finder
*/
public static ClassElement forName(String name) {
String p; // package
String n; // name
Repository rep = TopManager.getDefault ().getRepository ();
// 1. find XXX.class file
int index = name.lastIndexOf ('.');
if (index >= 0 && index <= name.length()) {
p = name.substring (0, index);
n = name.substring (index + 1);
}
else {
p = ""; // NOI18N
n = name;
}
FileObject fo = rep.find (p, n, "class"); // NOI18N
ClassElement element = testFileForName(fo, n);
if (element != null)
return element;
// 2. find XXX.java (e.g. org.netbeans.Outer.Inner)
index = n.indexOf('$');
if (index != -1) {
//2a. find inner if it is delimited by '$' e.g. org.netbeans.Outer$Inner
fo = rep.find(p, n.substring(0, index), "java"); // NOI18N
element = testFileForName(fo, n);
if (element != null)
return element;
}
else {
// 2b. find e.g. for org.netbeans.Outer.Inner
// => tries all: package - className
// ---------------------------------
// 1) org.netbeans.Outer - Inner
// 2) org.netbeans - Outer$Inner
// 3) com - netbeans$Outer$Inner
String nn = n;
for (;;) {
fo = rep.find(p, nn, "java"); // NOI18N
element = testFileForName(fo, n);
if (element != null)
return element;
index = p.lastIndexOf('.');
if ((index >= 0) && index <= p.length()) {
nn = p.substring(index + 1);
n = nn + "." + n; // NOI18N
p = p.substring (0, index);
}
else {
break;
}
}
}
// 3. find Class.forName() and calls forClass
try {
Class clazz = Class.forName(name);
return forClass(clazz);
}
catch (ClassNotFoundException e) {
return null;
}
}
/** Test whether for the specified fileObject exists dataobject,
* which has SourceCookie and contains the class of the given name.
* @param fo The tested fileObject, could be null
* @param name the name of class which should be in the source.
* @return The classElement for the given parameters or <CODE>null</CODE>.
*/
private static ClassElement testFileForName(FileObject fo, String name) {
if (fo != null) {
try {
DataObject obj = DataObject.find (fo);
SourceCookie sc = (SourceCookie) obj.getCookie (SourceCookie.class);
if (sc != null) {
ClassElement[] arr = sc.getSource ().getClasses ();
StringTokenizer tukac = new StringTokenizer(name, "$."); // NOI18N
while (tukac.hasMoreTokens()) {
String token = tukac.nextToken();
ClassElement c = null;
for (int i = 0; i < arr.length; i++) {
Identifier id = arr[i].getName();
if (id.getName().equals(token)) {
if (!tukac.hasMoreTokens()) {
return arr[i];
}
else {
c = arr[i];
break;
}
}
}
if (c == null)
return null;
else
arr = c.getClasses();
}
}
}
catch (DataObjectNotFoundException e) {
}
}
return null;
}
/** Search for a class element throughout the system.
* Asks all registered finders if they know where to find such a class.
* @param name class name separated by dots, e.g. <code>java.lang.String</code>
* @return class element for that name, or <code>null</code> if none exists
* @see ClassElement.Finder
*/
public static ClassElement forClass(Class clazz) {
synchronized (finders) {
Iterator it = finders.iterator ();
while (it.hasNext ()) {
ClassElement el = ((Finder)it.next()).find (clazz);
if (el != null)
return el;
}
}
return null;
}
/** Provides a "finder" for class elements.
* A module can provide its own finder to enhance the ability
* of the IDE to locate a valid class element description for different classes.
* @see ClassElement#forName
* @see ClassElement#register
* @see ClassElement#unregister
*/
public static interface Finder {
/** Find a class element description for a class.
*
* @param clazz the class to find
* @return the class element, or <code>null</code> if not found
*/
public ClassElement find(Class clazz);
}
// ================ implementation ===================================
/** Pluggable behavior for class elements.
* @see ClassElement
*/
public static interface Impl extends MemberElement.Impl {
/** Add some items. */
public static final int ADD = 1;
/** Remove some items. */
public static final int REMOVE = -1;
/** Set some items, replacing the old ones. */
public static final int SET = 0;
static final long serialVersionUID =2564194659099459416L;
/** Set the superclass for this class.
* @param superClass the superclass, by name
* @throws SourceException if impossible
*/
public void setSuperclass(Identifier superClass) throws SourceException;
/** Get the superclass for this class.
* @return the superclass, by name
*/
public Identifier getSuperclass();
/** Set whether this is a class or interface.
* @param isClass either {@link ClassElement#CLASS} or {@link ClassElement#INTERFACE}
* @throws SourceException if impossible
*/
public void setClassOrInterface(boolean isClass) throws SourceException;
/** Test whether this is a class or interface.
* @return either {@link ClassElement#CLASS} or {@link ClassElement#INTERFACE}
*/
public boolean isClassOrInterface();
/** Change the set of initializers.
* @param elems the new initializers
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeInitializers (InitializerElement[] elems, int action) throws SourceException;
/** Get all initializers.
* @return the initializers
*/
public InitializerElement[] getInitializers ();
/** Change the set of fields.
* @param elems the new fields
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeFields (FieldElement[] elems, int action) throws SourceException;
/** Get all fields.
* @return the fields
*/
public FieldElement[] getFields ();
/** Find a field by name.
* @param name the name to look for
* @return the field, or <code>null</code> if it does not exist
*/
public FieldElement getField (Identifier name);
/** Change the set of methods.
* @param elems the new methods
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeMethods (MethodElement[] elems, int action) throws SourceException;
/** Get all methods.
* @return the methods
*/
public MethodElement[] getMethods ();
/** Finds a method by signature.
* @param name the name to look for
* @param arguments the argument types to look for
* @return the method, or <code>null</code> if it does not exist
*/
public MethodElement getMethod (Identifier name, Type[] arguments);
/** Change the set of constructors.
* @param elems the new constructors
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeConstructors (ConstructorElement[] elems, int action) throws SourceException;
/** Get all constructors.
* @return the constructors
*/
public ConstructorElement[] getConstructors ();
/** Find a constructor by signature.
* @param arguments the argument types to look for
* @return the constructor, or <code>null</code> if it does not exist
*/
public ConstructorElement getConstructor (Type[] arguments);
/** Change the set of inner classes.
* @param elems the new inner classes
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeClasses (ClassElement[] elems, int action) throws SourceException;
/** Get all inner classes.
* @return the inner classes
*/
public ClassElement[] getClasses ();
/** Find an inner class by name.
* @param name the name to look for
* @return the inner class, or <code>null</code> if it does not exist
*/
public ClassElement getClass (Identifier name);
/** Change the set of implemented/extended interfaces.
* @param elems the new interfaces, by name
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
public void changeInterfaces (Identifier[] ids, int action) throws SourceException;
/** Get all implemented/extended interfaces.
* @return the interfaces, by name
*/
public Identifier[] getInterfaces ();
/** Get the class's documentation block.
* @return JavaDoc for the class (not its members)
*/
public JavaDoc.Class getJavaDoc();
}
/** Memory based implementation of the element factory.
*/
static final class Memory extends MemberElement.Memory implements Impl {
/** property, need not be initialized */
private Identifier superClass;
/** is class or interface */
private boolean isClass;
/** collection of interfaces */
private MemoryCollection interfaces;
/** collection of initializers */
private MemoryCollection.Initializer initializers;
/** collection of constructors */
private MemoryCollection.Constructor constructors;
/** collection of methods */
private MemoryCollection.Method methods;
/** collection of fields */
private MemoryCollection.Field fields;
/** collection of classes */
private MemoryCollection.Class classes;
/** memory implementation of java doc */
JavaDoc.Class javaDoc = null;
static final long serialVersionUID =6058485742932189851L;
public Memory () {
superClass = null;
isClass = true;
javaDoc = JavaDocSupport.createClassJavaDoc( null );
}
/** Copy constructor.
* @param el element to copy from
*/
public Memory (ClassElement el) {
super (el);
superClass = el.getSuperclass ();
isClass = el.isClassOrInterface ();
javaDoc = el.getJavaDoc().isEmpty() ?
JavaDocSupport.createClassJavaDoc( null ) :
JavaDocSupport.createClassJavaDoc( el.getJavaDoc().getRawText() );
}
/** Late initialization of initialization of copy elements.
*/
public void copyFrom (ClassElement copyFrom) {
changeInterfaces (copyFrom.getInterfaces (), SET);
changeConstructors (copyFrom.getConstructors (), SET);
changeMethods (copyFrom.getMethods (), SET);
changeFields (copyFrom.getFields (), SET);
changeClasses (copyFrom.getClasses (), SET);
}
/** Setter
*/
public void setSuperclass(Identifier superClass) throws SourceException {
Identifier old = this.superClass;
this.superClass = superClass;
firePropertyChange (PROP_SUPERCLASS, old, superClass);
}
public Identifier getSuperclass() {
return superClass;
}
public void setClassOrInterface(boolean isClass) {
boolean old = this.isClass;
this.isClass = isClass;
firePropertyChange (PROP_CLASS_OR_INTERFACE, new Boolean (old), new Boolean (isClass));
}
public boolean isClassOrInterface() {
return isClass;
}
/** Changes set of elements.
* @param elems elements to change
* @param action the action to do (ADD, REMOVE, SET)
* @exception SourceException if the action cannot be handled
*/
public synchronized void changeInitializers (InitializerElement[] elems, int action) {
initInitializers();
initializers.change (elems, action);
}
public synchronized InitializerElement[] getInitializers () {
initInitializers();
return (InitializerElement[])initializers.toArray ();
}
void initInitializers() {
if (initializers == null) {
initializers = new MemoryCollection.Initializer (this);
}
}
/** Changes set of elements.
* @param elems elements to change
* @exception SourceException if the action cannot be handled
*/
public synchronized void changeFields (FieldElement[] elems, int action) {
initFields();
fields.change (elems, action);
}
public synchronized FieldElement[] getFields () {
initFields();
return (FieldElement[])fields.toArray ();
}
/** Finds a field with given name.
* @param name the name of field to look for
* @return the element or null if field with such name does not exist
*/
public synchronized FieldElement getField (Identifier name) {
initFields();
return (FieldElement)fields.find (name, null);
}
void initFields() {
if (fields == null) {
fields = new MemoryCollection.Field (this);
}
}
/** Changes set of elements.
* @param elems elements to change
*/
public synchronized void changeMethods (MethodElement[] elems, int action) {
initMethods();
methods.change (elems, action);
}
public MethodElement[] getMethods () {
initMethods();
return (MethodElement[])methods.toArray ();
}
/** Finds a method with given name and argument types.
* @param name the name of field to look for
* @param arguments for the method
* @return the element or null if such method does not exist
*/
public synchronized MethodElement getMethod (Identifier name, Type[] arguments) {
initMethods();
return (MethodElement)methods.find (name, arguments);
}
void initMethods() {
if (methods == null) {
methods = new MemoryCollection.Method (this);
}
}
/** Changes set of elements.
* @param elems elements to change
* @exception SourceException if the action cannot be handled
*/
public synchronized void changeConstructors (ConstructorElement[] elems, int action) {
initConstructors();
constructors.change (elems, action);
}
public synchronized ConstructorElement[] getConstructors () {
initConstructors();
return (ConstructorElement[])constructors.toArray ();
}
/** Finds a constructor with argument types.
* @param arguments for the method
* @return the element or null if such method does not exist
*/
public synchronized ConstructorElement getConstructor (Type[] arguments) {
initConstructors();
return (ConstructorElement)constructors.find (null, arguments);
}
void initConstructors() {
if (constructors == null) {
constructors = new MemoryCollection.Constructor (this);
}
}
/** Changes set of elements.
* @param elems elements to change
*/
public synchronized void changeClasses (ClassElement[] elems, int action) {
initClasses();
classes.change (elems, action);
}
public synchronized ClassElement[] getClasses () {
initClasses();
return (ClassElement[])classes.toArray ();
}
/** Finds an inner class with given name.
* @param name the name to look for
* @return the element or null if such class does not exist
*/
public synchronized ClassElement getClass (Identifier name) {
initClasses();
return (ClassElement)classes.find (name, null);
}
void initClasses() {
if (classes == null) {
classes = new MemoryCollection.Class (this);
}
}
/** Changes interfaces this class implements (or extends).
* @param ids identifiers to change
*/
public synchronized void changeInterfaces (Identifier[] ids, int action) {
initInterfaces();
interfaces.change (ids, action);
}
/** @return all interfaces which this class implements or interface extends.
*/
public synchronized Identifier[] getInterfaces () {
initInterfaces();
return (Identifier[])interfaces.toArray ();
}
void initInterfaces() {
if (interfaces == null) {
interfaces = new MemoryCollection (this, PROP_INTERFACES, new Identifier[0]);
}
}
// ================ javadoc =========================================
/** @return class documentation.
*/
public JavaDoc.Class getJavaDoc() {
return javaDoc;
}
/** Getter for the associated class
* @return the class element for this impl
*/
final ClassElement getClassElement () {
return (ClassElement)element;
}
// ================ serialization ======================================
public Object readResolve() {
return new ClassElement(this, (SourceElement)null);
}
}
}
/*
* Log
* 41 Gandalf-post-FCS1.39.3.0 4/3/00 Svatopluk Dedic Bugfix #5821
* 40 src-jtulach1.39 1/18/00 Petr Hamernik bugfix of previous
* change
* 39 src-jtulach1.38 1/18/00 Petr Hamernik fixed #5309
* 38 src-jtulach1.37 1/12/00 Petr Hamernik i18n using perl script
* (//NOI18N comments added)
* 37 src-jtulach1.36 1/10/00 Petr Hamernik better formating
* (elements printing)
* 36 src-jtulach1.35 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 35 src-jtulach1.34 9/29/99 Petr Hamernik During adding elements
* is tested if they are already added (fixed bugs #3130, #1706)
* 34 src-jtulach1.33 9/27/99 Petr Hamernik indenting improved
* (empty lines between methods)
* 33 src-jtulach1.32 8/9/99 Ian Formanek Generated Serial Version
* UID
* 32 src-jtulach1.31 7/21/99 Petr Hamernik nullPointerExc bugfix
* 31 src-jtulach1.30 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 30 src-jtulach1.29 6/7/99 Petr Hrebejk Memory implementations
* added to memory implementations of elements
* 29 src-jtulach1.28 5/14/99 Jesse Glick [JavaDoc]
* 28 src-jtulach1.27 5/12/99 Petr Hamernik Identifier
* implementation updated
* 27 src-jtulach1.26 5/10/99 Petr Hamernik javadoc & printing
* improved
* 26 src-jtulach1.25 5/6/99 Petr Hamernik finding rewritten
* 25 src-jtulach1.24 4/27/99 Jesse Glick [JavaDoc]
* 24 src-jtulach1.23 4/27/99 Jaroslav Tulach find renamed to forName
* for Class.forName consistency
* 23 src-jtulach1.22 4/26/99 Jaroslav Tulach
* 22 src-jtulach1.21 4/20/99 Petr Hamernik synchronization of the
* name - between class and constructors
* 21 src-jtulach1.20 4/8/99 Jesse Glick [JavaDoc]
* 20 src-jtulach1.19 4/6/99 Jesse Glick [JavaDoc]
* 19 src-jtulach1.18 4/2/99 Petr Hamernik isApplet added
* 18 src-jtulach1.17 4/2/99 Petr Hamernik
* 17 src-jtulach1.16 4/2/99 Petr Hamernik
* 16 src-jtulach1.15 4/1/99 Petr Hamernik hasMainMethod
* 15 src-jtulach1.14 3/30/99 Jesse Glick [JavaDoc]
* 14 src-jtulach1.13 3/23/99 Petr Hamernik
* 13 src-jtulach1.12 3/22/99 Petr Hamernik printing changed
* 12 src-jtulach1.11 3/15/99 Petr Hamernik
* 11 src-jtulach1.10 3/15/99 Petr Hamernik
* 10 src-jtulach1.9 2/26/99 Petr Hamernik bugfixes
* 9 src-jtulach1.8 2/17/99 Petr Hamernik serialization changed.
* 8 src-jtulach1.7 2/16/99 Petr Hamernik bugfix - testing null
* values improved
* 7 src-jtulach1.6 2/8/99 Petr Hamernik
* 6 src-jtulach1.5 1/19/99 Jaroslav Tulach
* 5 src-jtulach1.4 1/19/99 Jaroslav Tulach
* 4 src-jtulach1.3 1/19/99 Jaroslav Tulach
* 3 src-jtulach1.2 1/19/99 Jaroslav Tulach
* 2 src-jtulach1.1 1/18/99 David Simonek property constants added
* 1 src-jtulach1.0 1/17/99 Jaroslav Tulach
* $
*/